#pragma once

#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Util.hpp"
#include "Log.hpp"
#include <string>
#include <unordered_map>

const static std::string sep_space = " ";
const static std::string sep_line = "\r\n";
const static std::string sep_kv = ": ";

const static std::string wwwroot = "./wwwroot";
const static std::string home_page = "/home.html";
const static std::string page_404 = "/404.html";

class HttpRequest
{
public:
    void ParseReqLine(std::string &req_line)
    {
        // GET / HTTP/1.1
        std::stringstream ss(req_line);
        ss >> _method >> _url >> _http_version;
    }

    bool Deserialize(std::string& req_str)
    {
        // 请求行
        std::string req_line;
        bool res = Util::ReadOneLine(req_str, &req_line, sep_line);
        if(!res)
            return false;
        ParseReqLine(req_line);
        LOG(LogLevel::DEBUG) << "reqline: " << req_line;

        if(_url == "/")
            _url = wwwroot + home_page; // "./wwwroot/home.html";
        else 
            _url = wwwroot + _url; // "./wwwroot/..."

        // 假设没有?后面的参数...

        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_url: " << _url;
        LOG(LogLevel::DEBUG) << "_http_version: " << _http_version;

        // 请求报头 请求正文 ...

        return true;
    }

    std::string GetUrl()
    {
        return _url;
    }

private:
    std::string _method;
    std::string _url;
    std::string _http_version;

    std::unordered_map<std::string, std::string> _headers;

    std::string _blank_line;

    std::string _text;
};

class HttpResponse
{
public:
    HttpResponse()
    :_blank_line(sep_line)
    ,_http_version("HTTP/1.1")
    {}

    // 实现: 成熟的http，应答做序列化，不要依赖任何第三方库！
    std::string Serialize()
    {
        std::string status_line = _http_version + sep_space + std::to_string(_code) + sep_space + _code_desc + sep_line;
        std::string headers;
        for(auto& header : _headers)
        {
            headers += header.first + sep_kv + header.second + sep_line;
        }

        return status_line + headers + _blank_line + _text;
    }

    void SetCode(int code)
    {
        _code = code;
        switch(code)
        {
            case 200:
                _code_desc = "OK";
                break;
            case 301:
                _code_desc = "Found";
                break;
            case 404:
                _code_desc = "Not Found";
                break;
            default:
                break;
        }
    }

    void SetHeaders(const std::string& key, const std::string& value)
    {
        auto it = _headers.find(key);
        if(it == _headers.end())
            _headers.insert({key,value});
    }
    
    // 默认访问的是.htm/.html文件

    void SetTargetFile(const std::string& file)
    {
        _target_file = file;
    }

    void SetText(const std::string text)
    {
        _text = text;
    }

    bool MakeResponse(uint16_t port)
    {
        // 浏览器要访问图标, 忽略他
        if(_target_file == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::INFO) << "用户请求图标: " << _target_file << "忽略他";
            return false;
        }
        
        bool res = Util::ReadFileContent(_target_file, &_text);
        if(!res)
        {
            LOG(LogLevel::WARNING) << "没有文件: " << _target_file << " , 404";

            SetCode(302); // 没有这个文件, 重定向到404

            SetHeaders("Location","http://124.221.189.63:"+std::to_string(port)+"/404.html");
        }
        else
        {
            LOG(LogLevel::WARNING) << "读取文件: " << _target_file; 

            SetCode(200); // 成功

            int file_size = Util::FileSize(_target_file);
            SetHeaders("Content-Length", std::to_string(file_size));
        }

        return true;
    }
    
private:
    std::string _http_version;
    int _code;
    std::string _code_desc;

    std::unordered_map<std::string, std::string> _headers;

    std::string _blank_line;

    std::string _text;

    // 其他属性
    std::string _target_file;
};

class Http
{
public:
    Http(uint16_t port)
    :_tsvrp(std::make_unique<TcpServer>(port))
    ,_port(port)
    {}

    void HandleHttpRequest(std::shared_ptr<Socket>& sockfd, const InetAddr& client)
    {
        LOG(LogLevel::DEBUG) << "收到新连接，准备读取请求"; 
        
        std::string http_req;
        int n = sockfd->Recv(&http_req); // 大概率一次读到完整的请求报文
        if(n > 0)
        {
            std::cout << "##########################" << std::endl;
            std::cout << http_req;
            std::cout << "##########################" << std::endl;

            HttpRequest req;
            HttpResponse resp;

            req.Deserialize(http_req);
            resp.SetTargetFile(req.GetUrl());
            if(resp.MakeResponse(_port))
            {
                sockfd->Send(resp.Serialize());
            }
        }
    }

    void Start()
    {
        _tsvrp->Start([this](std::shared_ptr<Socket>& sockfd, const InetAddr& client){
            this->HandleHttpRequest(sockfd, client);
        });
    }

private:
    std::unique_ptr<TcpServer> _tsvrp;
    uint16_t _port;
};